#include <iostream>
#include <boost/lexical_cast.hpp>
#include "pcap++/PcapOffline.h"
#include "pcap++/PcapLive.h"
#include "pcap++/config.h"
#include <pcap++/Packet.h>
#include <pcap++/DataLink.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <map>
#include <list>
#include <queue>

#define FRONT_ENGINE 4200

#include "udp_server.h"
#include "udp_sender.h"
#include "agent/agent.h"
#include "frame.h"
#include "FilterContainer.h"
#include "front/AcceptedFlow.h"
#include "connection/server.h"


FilterContainer g_filterContainer;
AcceptedFlow g_acceptedFlow;

class FrontServer : public serverTCP
{
public:
	FrontServer(int port) : serverTCP(port)
	{

	}
	void dataReceive(com::Block const& block, socketTCP* socket)
	{
		if(block.has_subscription())
		{
			BaseFilterPointer newFilter = createFilter(block.subscription());

			std::string agentname = block.subscription().agentname();

			g_filterContainer.addFilter(newFilter, agentname, socket);

			std::cout << "new subscription from " << agentname << std::endl;
		}
/*		if(block.has_subscription_heartbeat())
		{
			std::cout << "subscription_heartbeat=" << block.subscription_heartbeat().agentname() << std::endl;
			g_filterContainer.updateSubscriptionContainer(block.subscription_heartbeat().agentname());
		}*/

	}

};


void handle(pcappp::Pcap& pcap, pcappp::Packet const& packet)
{
	Frame frame(packet);

	if( ! frame.isOK())
		return;
	if(frame.IPprotocol() == TCP_PROTOCOL)
	{
		FlowID flow_id = frame.getFlowID();

		if(UDPSenderPointer udpSender = g_filterContainer.validate(frame))
		{
			g_acceptedFlow.add(flow_id, udpSender);

			com::Block block;
			block.mutable_flowpacket()->set_payload(packet.get_data(), packet.get_capture_length());
			block.mutable_flowpacket()->set_flowid(flow_id);
			udpSender->sendString(block);
		}
		else if(UDPSenderPointer udpSender = g_acceptedFlow.find(flow_id))
		{
			com::Block block;
			block.mutable_flowpacket()->set_payload(packet.get_data(), packet.get_capture_length());
			block.mutable_flowpacket()->set_flowid(flow_id);
			udpSender->sendString(block);
		}
	}
}

int main(int argc, char *argv[])
{
	FrontServer server(FRONT_ENGINE);

	sleep(1);
	Agent a("TestAgent1");
	Agent b("TestAgent2");
	Agent c("TestAgent3");
	sleep(2);

	pcappp::PcapOffline pcapFile("tcp/big.tcp");
	pcapFile.loop(handle);
	c.killTcpClient();
	sleep(10);
//	pcappp::PcapLive eth3("eth3");
//	eth3.loop(handle);

	return 0;
}
